import logging
import os
import time
from concurrent.futures import ThreadPoolExecutor
from contextlib import asynccontextmanager

import httpx
from fastapi import FastAPI, HTTPException, BackgroundTasks, Request
from mysql.connector import pooling

from app.config import settings
from app.schemas.pydantic_models import AutoResponseRequest
from app.services.file_service import process_file_task
from app.utils import db_utils

# --- Logging Configuration ---
log_dir = "logs"
os.makedirs(log_dir, exist_ok=True)
log_file = os.path.join(log_dir, f"log_{time.strftime('%Y%m%d')}.log")
log_format = "%(asctime)s - %(levelname)s - %(message)s"
logging.basicConfig(
    level=logging.INFO,
    format=log_format,
    handlers=[logging.StreamHandler(), logging.FileHandler(log_file, encoding="utf-8")],
)

# --- Temporary Directory Setup ---
tmp_directory = settings.tmp_directory


@asynccontextmanager
async def lifespan(app: FastAPI):
    """
    Manages the application's lifespan.
    Initializes resources on startup and cleans them up on exit.
    """
    # --- Startup ---
    logging.info("Application starting...")

    # Create temporary file directory
    os.makedirs(tmp_directory, exist_ok=True)
    logging.info(f"Temporary file directory: '{tmp_directory}'")

    # Initialize the ThreadPoolExecutor for LLM calls and attach it to the app's state.
    app.state.llm_executor = ThreadPoolExecutor(
        max_workers=settings.llm_thread_pool_max_worker,
        thread_name_prefix='LLM_Worker'
    )
    logging.info(f"LLM thread pool initialized with {settings.llm_thread_pool_max_worker} workers.")

    # Initialize the db pool
    try:
        db_config = {
            "host": settings.db_host,
            "user": settings.db_user,
            "password": settings.db_password,
            "database": settings.db_name,
        }
        db_utils.cnx_pool = pooling.MySQLConnectionPool(
            pool_name="rfp_pool",
            pool_size=settings.db_pool_size,
            **db_config
        )
        logging.info(f"Mysql Db Population initialized with {settings.db_pool_size} connections")
    except Exception as e:
        logging.error(f"init db connection pool failed: {e}", exc_info=True)
        raise e

    yield

    # --- Shutdown ---
    app.state.llm_executor.shutdown(wait=True)
    logging.info("LLM thread pool has been shut down.")
    logging.info("Application shutting down")


# Create the FastAPI app instance with the lifespan manager.
app = FastAPI(lifespan=lifespan)


@app.post("/rfp/autoResponse")
async def rfp_auto_response(
        request: Request, request_data: AutoResponseRequest, background_tasks: BackgroundTasks
):
    """
    Receives a file URL, downloads it, and starts a background processing task.
    """
    file_url = str(request_data.fileUrl)
    sender_email = request_data.senderEmail
    original_filename = request_data.name
    language = request_data.language
    logging.info(
        f"Received new request: fileUrl='{file_url}', senderEmail='{sender_email}', name='{original_filename}', language='{language}'")

    # --- File Download Logic ---
    timestamp = int(time.time() * 1000)
    tmp_subdir = os.path.join(tmp_directory, f"tmp_{timestamp}")
    os.makedirs(tmp_subdir, exist_ok=True)
    unique_filename = f"{timestamp}_{original_filename}"
    file_path = os.path.join(tmp_subdir, unique_filename)

    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(file_url, follow_redirects=True, timeout=60.0)
            response.raise_for_status()
            with open(file_path, "wb") as f:
                f.write(response.content)
        logging.info(f"File successfully downloaded to: {file_path}")
    except httpx.RequestError as e:
        logging.error(f"Network error occurred while downloading file: {e.request.url!r} - {e}")
        raise HTTPException(
            status_code=400, detail=f"Unable to download file from the provided URL: Network error."
        )
    except httpx.HTTPStatusError as e:
        logging.error(
            f"Server returned error status code while downloading file: {e.response.status_code} for url {e.request.url!r}"
        )
        raise HTTPException(
            status_code=400,
            detail=f"Unable to download file, server returned error: {e.response.status_code}",
        )
    except Exception as e:
        logging.error(f"Unknown error occurred while downloading or saving file: {e}")
        raise HTTPException(status_code=500, detail="Internal error occurred while processing the file.")

    # --- Background Task Scheduling ---
    llm_executor = request.app.state.llm_executor

    # Add the processing task to run in the background, passing the executor instance.
    background_tasks.add_task(process_file_task, file_path, sender_email, tmp_subdir,
                              language, llm_executor)

    return {"status": "ok", "message": "File received, processing task started in background."}


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=8000)
